<?php
/*
 * Created on 2012-4-25
 * iChying
 * To change the template for this generated file go to
 * Window - Preferences - PHPeclipse - PHP - Code Templates
 */
	class ExtBase64Compression {
		private $encode_string;
		private $decode_string;

		// array
		private static $encode_table;
		private static $decode_table;
		private static $hex_table;
		private static $dec_to_hex;

		public function init() {
			self::generate_encode_table();
			self::generate_decode_table();
			self::generate_hex_table();
		}

		private static function generate_encode_table() {
			self::$encode_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
		}

		// generate the decode table
		private static function generate_decode_table() {
			// generate the bit operate array;
			function gen_array($value) {
				$bit_val1 = $value;
				$bit_val2 = ($value & 0x3c) >> 2;
				$bit_val3 = ($value & 0x03) << 2;
				$bit_val4 = ($value & 0x30) >> 4;
				$bit_val5 = ($value & 0x0f);
				$bit_val6 = ($value & 0x3c) >> 2;

				return array($bit_val1, $bit_val2, $bit_val3, $bit_val4, $bit_val5, $bit_val6);
			}

			self::$decode_table = array();

			// A-Z
			for ($i = 0; $i <= 25; ++$i) {
 				$_array = gen_array($i);
 				self::$decode_table[chr(ord('A') + $i)] = $_array;
 			}

			// a-z
 			for ($i = 26, $j = 0; $i <= 51; ++$i, ++$j) {
 				$_array = gen_array($i);
 				self::$decode_table[chr(ord('a') + $j)] = $_array;
 			}

			// 0-9
 			for ($i = 52, $j = 0; $i <= 61; ++$i, ++$j) {
 				$_array = gen_array($i);
 				self::$decode_table[chr(ord('0') + $j)] = $_array;
 			}

			// +
 			$_array = gen_array(62);
 			self::$decode_table['+'] = $_array;

			// /
			$_array = gen_array(63);
 			self::$decode_table['/'] = $_array;
 			// var_dump(self::$decode_table);
		}

		// generate the hexadecimal bit operate table
		private static function generate_hex_table() {
			self::$hex_table = array();
			self::$dec_to_hex = array();

			// 0~9
			for ($i = 0; $i <= 9; ++$i) {
				self::$dec_to_hex[] = chr(ord('0') + $i);

				$_value1 = ($i & 0x0c) >> 2;
				$_value2 = ($i & 0x03);
				$_array = array(($_value1 | 0x08), ($_value2 << 2), $_value1, ($_value2 | 0x08));

				self::$hex_table[chr((ord('0') + $i))] = $_array;
			}

			// a~f
			for ($i = 10, $j = 0; $i <= 15; ++$i, ++$j) {
				self::$dec_to_hex[] = chr(ord('a') + $j);

				$_value1 = ($i & 0x0c) >> 2;
				$_value2 = ($i & 0x03);
				$_array = array(($_value1 | 0x08), ($_value2 << 2), $_value1, ($_value2 | 0x08));

				self::$hex_table[chr((ord('a') + $j))] = $_array;
			}

			// var_dump(self::$dec_to_hex);
			// var_dump(self::$hex_table);
		}

		// convert to Unicode xxxx
		private static function UTF8ToUnicode($str) {
			$unicode_str = "";
			$str_length = strlen($str);

			for ($i = 0; $i < $str_length; $i += 9) {
				$str1 = hexdec(substr($str, $i + 1, 2)) & 0x0F;
				$str2 = hexdec(substr($str, $i + 4, 2)) & 0x3F;
				$str3 = hexdec(substr($str, $i + 7, 2)) & 0x3F;

				$dec_str = ($str1 << 12) | ($str2 << 6) | $str3;

				$unicode_str .= dechex($dec_str);
			}

			return $unicode_str;
		}

		public function compress($str) {
			$this->encode_string = "";

			$utf8_str = urlencode($str);
			// echo $str."<br />".$utf8_str."<br />";

			$php_encode_str = self::UTF8ToUnicode($utf8_str);
			// echo strlen($php_encode_str)." ".$php_encode_str."<br />";

			$str_length = strlen($php_encode_str);
			//echo $str_length."<br />";

			for ($i = 0; $i < $str_length; $i += 4) {

				$sub_str = substr($php_encode_str, $i, 4);

				$bin_str = hexdec($sub_str) << 2;

				if (($bin_str & 0x00F80) == 0x00F80) {
					$bin_str = ($bin_str & 0xFFDFF) | 0x00001;
				}

				//0x3F 0011 1111
				$num_3 = $bin_str & 0x0003F;
				//0xFC0 1111 1100 0000
				$num_2 = ($bin_str & 0x0FC0) >> 6;
				// 0x3F000 0011 1111 0000 0000 0000
				$num_1 = ($bin_str & 0x3F000) >> 12;

				// echo 'num_1 = '.$num_1." num2 = ".$num_2." num3 = ".$num_3."<br />";

				$str_1 = self::$index_table[$num_1];
				$str_2 = self::$index_table[$num_2];
				$str_3 = self::$index_table[$num_3];
				//echo 'num_1 = '.$str_1." num2 = ".$str_2." num3 = ".$str_3."<br />";
				$encode_string .= $str_1.$str_2.$str_3;
			}
			// echo strlen($encode_string)." ".$encode_string."<br />";
			return $encode_string;
		}

		public function decompress($encode_string) {
			$unicode = '';
			$hex_alphabet = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
			$encode_str_length = strlen($encode_string);

			for ($i = 0; $i < $encode_str_length; $i += 3) {
				$ch1 = $encode_string[$i];
				$ch2 = $encode_string[($i + 1)];
				$ch3 = $encode_string[($i + 2)];

				$base_value2 = self::$decode_table[$ch2][0];
				$base_value3 = self::$decode_table[$ch3][0];

				if ($base_value3 & 0x1) {
					$base_value2 = $base_value2 | 0x08;
					$ch2 = self::$encode_table[$base_value2];
				}

				$de_idx1 = self::$decode_table[$ch1][1];
				$de_idx2 = (self::$decode_table[$ch1][2]) | (self::$decode_table[$ch2][3]);
				$de_idx3 = self::$decode_table[$ch2][4];
				$de_idx4 = self::$decode_table[$ch3][5];

				$unicode .= ($hex_alphabet[$de_idx1].$hex_alphabet[$de_idx2].$hex_alphabet[$de_idx3].$hex_alphabet[$de_idx4]);
			}

			$unicode = self::UCSToUTF8($unicode);
			$utf8 = urldecode($unicode);

			return $utf8;
		}

		/*
		 * convert to utf8 encode
		 * just use for chinese character
		 * unicode range 0x0800~0xffff
		 * utf-8 format:
		 * 1000 xxxx
		 * 10xx xxxx
		 * 10xx xxxx
		 */
		private static function UCSToUTF8($unicode) {
			$unicode_length = strlen($unicode);
			$UTF8 = '';

			// four character one process
			for ($i = 0; $i < $unicode_length; $i += 4) {
				$utf8_part1 = 'e'.$unicode[$i];

				$ch2 = $unicode[($i + 1)];
				$ch3 = $unicode[($i + 2)];

				// bit operate in table
				$idx_1 = self::$hex_table[$ch2][0];
				$idx_2 = (self::$hex_table[$ch2][1]) | (self::$hex_table[$ch3][2]);
				$idx_3 = self::$hex_table[$ch3][3];

				// dechex in table
				$utf8_part2 = self::$dec_to_hex[$idx_1].self::$dec_to_hex[$idx_2];
				$utf8_part3 = self::$dec_to_hex[$idx_3].$unicode[($i + 3)];

				// %xx%xx%xx
				$UTF8 .= ('%'.$utf8_part1).('%'.$utf8_part2).('%'.$utf8_part3);
			}

			return $UTF8;
		}
	}
?>